#include <stdio.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <errno.h>
#include "event.h"
#include "thpool.h"
#include "jobqueue.h"

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

void thpool_jobqueue_init(thpool_t *thpool){
	thpool->jobqueue = (thpool_jobqueue *)malloc(sizeof(thpool_jobqueue));
	if(thpool->jobqueue == NULL){
		outputError(errno,"%s","malloc jobqueue");
	}

	thpool->jobqueue->head = NULL;
	thpool->jobqueue->tail = NULL;
	thpool->jobqueue->jobN = 0;
	thpool->jobqueue->queueSem = (sem_t *)malloc(sizeof(sem_t));
	if(thpool->jobqueue->queueSem == NULL){
		outputError(errno,"%s","malloc sem");
	}
	sem_init(thpool->jobqueue->queueSem,0,0);
}

void *job_handle(void *arg){
	thpool_t *thpool;
	thpool_job_t *job;
	FUNC func;
	handle_event_msg_t *msg;
	int s;

	thpool = (thpool_t *)arg;

	while(1){
		if(sem_wait(thpool->jobqueue->queueSem) == -1){
			outputError(errno,"%s","sem_wait error");
		}
		s = pthread_mutex_lock(&mtx);
		job = remove_jobqueue(thpool);
		s = pthread_mutex_unlock(&mtx);

		func = job->function;
		msg = (handle_event_msg_t *)job->arg;
		func(msg);

		free(msg);
		free(job);
	}
}

thpool_job_t *remove_jobqueue(thpool_t *thpool){
	thpool_job_t *job;

	if(thpool->jobqueue->jobN == 0){
		return NULL;
	}

	job = thpool->jobqueue->head;
	thpool->jobqueue->jobN--;
	thpool->jobqueue->head = thpool->jobqueue->head->next;
	thpool->jobqueue->head == NULL ? (thpool->jobqueue->tail = NULL) : (thpool->jobqueue->head->prev = NULL);

	return job;
}

int insert_jobqueue(thpool_t *thpool,event_handler_t *eh,handle_event_msg_t arg){
	thpool_job_t *job,tmp;
	int s;

	job = (thpool_job_t *)malloc(sizeof(thpool_job_t));
	if(job == NULL){
		outputError(errno,"%s","malloc thpool_job_t");
	}

	job->function = eh->handle_event;
	job->arg = (handle_event_msg_t *)malloc(sizeof(handle_event_msg_t));
	if(job->arg == NULL){
		outputError(errno,"%s","malloc handle_event_msg_t");
	}
	*(handle_event_msg_t *)(job->arg) = arg;

	if(thpool->jobqueue->jobN == 0){
		s = pthread_mutex_lock(&mtx);
		if(s != 0){
			outputError(s,"%s","mtx lock");
		}
		thpool->jobqueue->tail = thpool->jobqueue->head = job;
		job->prev = job->next = NULL;
		thpool->jobqueue->jobN++;
		s = pthread_mutex_unlock(&mtx);
		if(s != 0){
			outputError(s,"%s","mtx unlock");
		}
	}else{
		s = pthread_mutex_lock(&mtx);
		if(s != 0){
			outputError(s,"%s","mtx lock");
		}
		thpool->jobqueue->jobN++;
		thpool->jobqueue->tail->next = job;
		job->next = NULL;
		job->prev = thpool->jobqueue->tail;
		thpool->jobqueue->tail = thpool->jobqueue->tail->next;
		s = pthread_mutex_unlock(&mtx);
		if(s != 0){
			outputError(s,"%s","mtx unlock");
		}
	}

	sem_post(thpool->jobqueue->queueSem);
}
